package com.atguigu.srb.core.service.impl;

import com.atguigu.srb.base.util.Asserts;
import com.atguigu.srb.base.util.JwtUtils;
import com.atguigu.srb.common.result.ResponseEnum;
import com.atguigu.srb.core.entity.BorrowInfo;
import com.atguigu.srb.core.entity.Borrower;
import com.atguigu.srb.core.entity.Lend;
import com.atguigu.srb.core.entity.UserInfo;
import com.atguigu.srb.core.entity.vo.BorrowInfoApprovalVo;
import com.atguigu.srb.core.entity.vo.BorrowInfoVo;
import com.atguigu.srb.core.entity.vo.BorrowerDetailVo;
import com.atguigu.srb.core.entity.vo.BorrowerVo;
import com.atguigu.srb.core.enums.LendStatusEnum;
import com.atguigu.srb.core.mapper.BorrowInfoMapper;
import com.atguigu.srb.core.mapper.DictMapper;
import com.atguigu.srb.core.service.*;
import com.atguigu.srb.core.util.LendNoUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.autoconfigure.web.ConditionalOnEnabledResourceChain;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.xml.crypto.Data;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 借款信息表 服务实现类
 * </p>
 *
 * @author Atguigu
 * @since 2023-06-30
 */
@Service
public class BorrowInfoServiceImpl extends ServiceImpl<BorrowInfoMapper, BorrowInfo> implements BorrowInfoService {
    @Resource
    IntegralGradeService integralGradeService;
    @Resource
    UserInfoService userInfoService;
    @Resource
    DictMapper dictMapper;
    @Resource
    BorrowerService borrowerService;
    @Resource
    LendService lendService;

    // 提交用户的借款申请
    @Override
    public void commitApplication(BorrowInfo borrowInfo, String token) {
        // 1.首先根据token获取里面的userId
        // Long userId = JwtUtils.getUserId(token);
        // 对借款会员进行检查 : 账户是否被锁定已经在拦截器中检查过了
        // 账户必须已经绑定了hfb的账户了,抽取这里的方法到userInfo里面
        UserInfo userInfo = userInfoService.checkUserInfoByToken(token);
        Long userId = userInfo.getId();

        // 还需要校验借款人是否存在未完成的借款记录,如果存在直接抛出异常
        int count = this.count(Wrappers.lambdaQuery(BorrowInfo.class).eq(BorrowInfo::getUserId, userId)
                .in(BorrowInfo::getStatus, 0, 1, -1, 2));
        Asserts.AssertNotTrue(count > 0, ResponseEnum.BORROW_INFO_EXISTS_ERROR);
        //Asserts.assertTrue(count==0 , ResponseEnum.BORROW_INFO_EXISTS_ERROR); 这个写法也是可以的,一样的

        // 2.需要对borroweInfo的参数进行校验
        // 2.1 amount不能为0,也不能为null
        Asserts.AssertNotTrue(borrowInfo.getAmount() == null || borrowInfo.getAmount().intValue() == 0
                , ResponseEnum.BORROW_AMOUNT_NULL_ERROR);
        // 2.2 amount的不能超过限制的借款的金额
        // 2.2.1获取借款人的可借款的金额
        BigDecimal amount = integralGradeService.getAmount(token);
        // 2.2.2比较申请的金额和可借款的金额
        Asserts.AssertNotTrue(borrowInfo.getAmount().doubleValue() > amount.doubleValue(), ResponseEnum.USER_AMOUNT_LESS_ERROR);

        // 3.borrowInfo查询数据库之前需要先设置一些前端没有传过来的属性
        // 3.1设置状态 "状态（0：未提交，1：审核中， 2：审核通过， -1：审核不通过 3 : 已关闭  4 : 已完成） 这里应该是1审核中
        borrowInfo.setStatus(1);
        // 3.2设置userId
        borrowInfo.setUserId(userId);

        // 4.将borrowerInfo对象插入到数据库中
        this.save(borrowInfo);
    }

    @Override
    public Integer getBorrowStatus(String token) {
        // 根据token获取用户的userId
        Long userId = JwtUtils.getUserId(token);
        // 根据用户的id查询borrowInfo里面的status
        BorrowInfo borrowInfo = this.getOne(Wrappers.lambdaQuery(BorrowInfo.class).eq(BorrowInfo::getUserId, userId)
                // 这里不查询状态已关闭和已完成的情况
                .in(BorrowInfo::getStatus, 0, -1, 1, 2));
        return borrowInfo == null ? 0 : borrowInfo.getStatus();
    }

    @Override
    public List<BorrowInfoVo> getLists() {
        // 获取对应的信息
        List<BorrowInfoVo> lists = baseMapper.getBorrowLists();
        lists.forEach(borrowInfoVo -> {
            Map<String, String> params = borrowInfoVo.getParams();
            // 设置借款期限
            params.put("period", borrowInfoVo.getPeriod() + "个月");
            // 设置还款方式 还款方式 1-等额本息 2-等额本金 3-每月还息一次还本 4-一次还本
            String returnMethod = dictMapper.getDictNameByDictCodeAndValue("returnMethod", borrowInfoVo.getReturnMethod());
            params.put("returnMethod",returnMethod);
            //设置资金用途
            String moneyUse = dictMapper.getDictNameByDictCodeAndValue("moneyUse", borrowInfoVo.getMoneyUse());
            params.put("moneyUse",moneyUse);
            //设置年化利率
            params.put("borrowYearRate",borrowInfoVo.getBorrowYearRate()+"%");
            //设置状态 状态（0：未提交，1：审核中， 2：审核通过， -1：审核不通过 ，3: 已关闭 , 4：已完成）
            String status = null;
            switch (borrowInfoVo.getStatus()){
                case 0:
                    status = "未提交";
                    break;
                case 1:
                    status = "审核中";
                    break;
                case 2:
                    status = "审核通过";
                    break;
                case -1:
                    status = "审核不通过";
                    break;
                case 3:
                    status = "已关闭";
                    break;
                default:
                    status = "已完成";
                    break;
            }
            params.put("status",status);
        });
        return lists;
    }

    @Override
    public Map<String, Object> getBorrowDetail(Long id) {
        Map<String,Object> map = new HashMap<>();

        //此处的id是borrow的id
        //1.borrowInfo BorrowInfoVo
        BorrowInfo borrowInfo = this.getById(id);
        //1.1复制属性到borrowInfo里面去
        BorrowInfoVo borrowInfoVo = new BorrowInfoVo();
        BeanUtils.copyProperties(borrowInfo,borrowInfoVo);
        //1.2设置borrowInfoVo里面的params属性 借款期限,年化利率,还款方式,资金用途,状态
        //1.2.1 借款期限
        Map<String, String> params = borrowInfoVo.getParams();
        params.put("period", borrowInfoVo.getPeriod() + "个月");
        //1.2.2 设置还款方式 还款方式 1-等额本息 2-等额本金 3-每月还息一次还本 4-一次还本
        String returnMethod = dictMapper.getDictNameByDictCodeAndValue("returnMethod", borrowInfoVo.getReturnMethod());
        params.put("returnMethod",returnMethod);
        //1.2.3设置资金用途
        String moneyUse = dictMapper.getDictNameByDictCodeAndValue("moneyUse", borrowInfoVo.getMoneyUse());
        params.put("moneyUse",moneyUse);
        //1.2.4设置年化利率
        params.put("borrowYearRate",borrowInfoVo.getBorrowYearRate()+"%");
        //1.2.5设置状态 状态（0：未提交，1：审核中， 2：审核通过， -1：审核不通过 ，3: 已关闭 , 4：已完成）
        String status = null;
        switch (borrowInfoVo.getStatus()){
            case 0:
                status = "未提交";
                break;
            case 1:
                status = "审核中";
                break;
            case 2:
                status = "审核通过";
                break;
            case -1:
                status = "审核不通过";
                break;
            case 3:
                status = "已关闭";
                break;
            default:
                status = "已完成";
                break;
        }
        params.put("status",status);

        map.put("borrowInfo",borrowInfoVo);

        //2.borrower  BorrowerDetailVo
        //目前已知的信息是borrowInfo的id,我们可以根据此id查询出来borrowerInfo,进而获得userId
        //borrowerServiceImpl里面有根据borrowerId获取borrowerVo信息的方法,魔改一下那个方法
        //变成根据userId获取borrowerVo的信息
        Long userId = this.getById(id).getUserId();
        BorrowerDetailVo borrowerDetailVo = borrowerService.getDetailByUserId(userId);

        map.put("borrower",borrowerDetailVo);
        return map;
    }

    //借款审批
    @Override
    public void approval(BorrowInfoApprovalVo borrowInfoApprovalVo) {
        //1.校验相关的参数
        //1.1获取borroInfoId
        Long borrowInfoId = borrowInfoApprovalVo.getBorrowInfoId();
        //1.2获取borrowInfo对象
        BorrowInfo borrowInfo = this.getById(borrowInfoId);
        //1.3获取userId
        Long userId = borrowInfo.getUserId();

        UserInfo userInfo = userInfoService.getById(userId);
        //1.4 校验参数
        //1.4.1 用户的账户状态必须是可用的,而且有绑定hfb的账户
        //断言为NotTrue才放行,那么为true会抛异常, 为true就意味着 要么账户被锁定了,要么还没有绑定hfb的账户
        Asserts.AssertNotTrue(userInfo.getStatus() != 1 || userInfo.getBindStatus() != 1,ResponseEnum.LOGIN_LOCKED_ERROR);

        //1.4.2 该借款申请的状态必须是审核中的,其他的状态不可以 0：未提交，1：审核中， 2：审核通过， -1：审核不通过  3: 已关闭  4: 已完成
        Asserts.AssertNotTrue(borrowInfo.getStatus() != 1,ResponseEnum.BORROW_INFO_STATUS_ERROR);

        //更新借款申请的状态borrowInfo status
        borrowInfo.setStatus(borrowInfoApprovalVo.getStatus());
        this.updateById(borrowInfo);

        //根据borrowInfo的状态来决定是否继续往下执行(如果没通过就不往下执行了)
        if(borrowInfoApprovalVo.getStatus() == 2) {
        //只有当状态是2的时候才会继续执行
            //2.复制vo里面的属性到lend里面
            Lend lend = new Lend();
            BeanUtils.copyProperties(borrowInfoApprovalVo, lend);

            //2.1设置lend其余的属性
            lend.setUserId(userId);//设置用户的id
            lend.setBorrowInfoId(borrowInfoId);//设置borrow信息的的id
            lend.setLendNo(LendNoUtils.getLendNo());//标的编号,和id一样,都需要我们后端来生成
            lend.setTitle(borrowInfoApprovalVo.getTitle());//设置标的的标题
            lend.setAmount(borrowInfo.getAmount());//获取标的的金额
            lend.setPeriod(borrowInfo.getPeriod());//获取标的的投资期数
            lend.setLendYearRate(borrowInfoApprovalVo.getLendYearRate());//获取标的的年化利率
            lend.setServiceRate(borrowInfoApprovalVo.getServiceRate());//获取标的的平台服务费率
            lend.setReturnMethod(borrowInfo.getReturnMethod());//获取还款方式
            lend.setLowestAmount(new BigDecimal(50));//设置最低的投资金额
            lend.setInvestAmount(new BigDecimal(0));//设置已投资的金额
            lend.setInvestNum(0);//设置已投资的人数
            lend.setPublishDate(new Date());//设置发布的日期
            lend.setLendStartDate(new DateTime(borrowInfoApprovalVo.getLendStartDate()).toDate());//起息日
            //结束日期 = 起息日 + 期数(月数)
            Date date = new DateTime(lend.getLendStartDate()).plusMonths(borrowInfo.getPeriod()).toDate();
            lend.setLendEndDate(date);
            lend.setLendInfo(borrowInfoApprovalVo.getLendInfo());
            //平台预期收益 = 标的金额 * 平台服务费率 * 期数 / (12 * 100)   四舍五入
            BigDecimal expectAmount = lend.getAmount().multiply(lend.getServiceRate())
                    .multiply(new BigDecimal(borrowInfo.getPeriod())).divide(new BigDecimal(1200), 8, BigDecimal.ROUND_DOWN);
        /* BigDecimal monthServiceRate = serviceRate.divide(new BigDecimal(1200), 8, BigDecimal.ROUND_DOWN);
        BigDecimal expectAmunt = borrowInfo.getAmount().multiply(new BigDecimal(borrowInfo.getPeriod()))
                .multiply(monthServiceRate); */
            lend.setExpectAmount(expectAmount);
            lend.setRealAmount(new BigDecimal(0));//实际收益
            lend.setStatus(LendStatusEnum.INVEST_RUN.getStatus());//标的的状态,募资中
            lend.setCheckTime(new Date());//审核时间
            lend.setCheckAdminId(1L);//审批管理员的id(此时还没有管理员的id,先给假数据)
            //放款时间和放款人id暂时也没有

            //将lend插入到数据库中保存
            lendService.save(lend);
        }
    }
}
